This session will continue with the exploration of some of the tkinter widgets mentioned last time.
Features:

To create Radiobutton widgets we use tkinter module's Radiobutton class. At any time, only one of the Radiobutton widgets in a given container (e.g., a Frame) may be selected. Clicking a Radiobutton selects it and automatically deselects any other Radiobutton in the same container. Because only one Radiobutton in a container can be selected at any given time, they are said to be mutually exclusive.
The tkinter module provides a class named IntVar that can be used along with Radiobutton widgets (recall that in the previous session we encountered StringVar objects). When we create a group of Radiobuttons, we associate them all with the same IntVar object; we also have to assign a unique integer value to each such button widget. When one of the Radiobutton widgets is selected, it stores its unique integer value in the IntVar object.
This is illustrated in the next example:
# This program demonstrates
# a group of Radiobutton widgets.
import tkinter
import tkinter.messagebox
# Create the main window:
root = tkinter.Tk()
# The show_choice function is
# the callback function for the OK button:
def show_choice():
tkinter.messagebox.showinfo('Selection',
'You selected option '+str(radio_var.get()))
# Create two frames. One for the Radiobuttons
# and another for the regular Button widgets:
top_frame = tkinter.Frame(root)
bottom_frame = tkinter.Frame(root)
# Create an IntVar object to use
# with the Radiobuttons:
radio_var = tkinter.IntVar()
# Set the intVar object to 1.
radio_var.set(0)
# Create the Radiobutton widgets in the top_frame:
rb1 = tkinter.Radiobutton(top_frame,
text='Option 1',
variable=radio_var,
value=1)
rb2 = tkinter.Radiobutton(top_frame,
text='Option 2',
variable=radio_var,
value=2)
rb3 = tkinter.Radiobutton(top_frame,
text='Option 3',
variable=radio_var,
value=3)
# Pack the Radiobuttons:
rb1.pack()
rb2.pack()
rb3.pack()
# Create an OK button and a Quit button:
ok_button = tkinter.Button(bottom_frame,
text='OK',
command=show_choice)
quit_button = tkinter.Button(bottom_frame,
text='Quit',
command=root.destroy)
# Pack the Buttons:
ok_button.pack(side='left')
quit_button.pack(side='left')
# Pack the frames:
top_frame.pack()
bottom_frame.pack()
# Start the mainloop:
root.mainloop()
In the example discussed above the program waits for the user to click the 'OK' button before it determines which Radiobutton was selected; that happened because the callback function was associated to the 'OK' button rather than the radio buttons. Of course, we can specify a callback function with Radiobutton widgets as well.
For example, in the above code we can modify the definitions of all the radio buttons by adding at the end 'command = show_choice' that creates an association between the Radiobutton widget and our own function 'show_choice()'. In this case we won't need the 'OK' button, and the behaviour of the app will be different: whenever we make a selection, the info dialog box will pop up and display the option that has been chosen. In this case we do not need the 'OK' button because its behaviour is redundant now.
rb1 = tkinter.Radiobutton(top_frame,
text='Option 1',
variable=radio_var,
value=1,
command=show_choice)
There are situations in which we have to define more than 2-3 radio buttons. It would be rather cumbersome to define and write the code for each button separately. In such cases it makes sense to take advantage of Python's flexibility in handling loops, as illustrated in the next example.
Let's assume that we want to write a GUI program for selecting a topping for a pizza. There are many options that have to be listed (e.g., mushroom, bacon, cheese, etc), and we would like to have a Radiobutton widget for each. To simplify the writing of the code we could define a list of tuples that holds the text that has to be displayed next to each button as well as its corresponding value. Study the code included below:
# Illustrates the use of loops to create
# all the radio buttons
from tkinter import * # simplifies the syntax
import tkinter.messagebox # needed for the info dialog box
root = Tk() # the main window
radio_var = IntVar() # global variable (see above)
radio_var.set(0) # initialize choice (i.e., none)
# Define a list of tuples to simplify
# the definitions of the radio buttons below.
# Each tuple contains the text that is to be displayed next
# to the button, as well as its corresponding value:
toppings = [
("Pepperoni", 1),
("Mushrooms", 2),
("Onions", 3),
("Sausage", 4),
("Bacon", 5),
("Extra cheese", 6),
("Black olives", 7),
("Green peppers", 8)
]
# callback function associated with the radio buttons:
def show_choice():
i = radio_var.get()
name = toppings[i-1][0]
tkinter.messagebox.showinfo('Selection',
'You selected option:\n' + name)
# The text to be displayed at the top of
# the selection menu:
mylabel = Label(root,
text="Choose your favourite topping:\n",
padx=20)
mylabel.pack()
# generate the buttons via a loop:
# (the preferred way when you have more than a 2-3 buttons)
for topping, val in toppings:
rb = Radiobutton(root,
text=topping,
padx=20,
variable=radio_var,
command=show_choice,
value=val)
rb.pack(anchor=W)
# we want all of our radio buttons to be left-justified
# start the event loop
root.mainloop()

A check button appears as a small box with a label next to it.

Features:
To create Checkbutton widgets we use tkinter module's Checkbutton class. As with Radiobuttons, we use an IntVar object along with a Checkbutton widget. However, unlike Radiobuttons, we associate a different IntVar object with each Checkbutton; when a Checkbutton is selected, its associated IntVar object will hold the value 1, while when it is deselected (or not selected), its associated IntVar object will hold the value 0.
# This program demonstrates a group of Checkbutton widgets
import tkinter
import tkinter.messagebox
# Create the main window:
root = tkinter.Tk()
# The callback function for the 'OK' button:---------------
def show_choice():
# Create a message string:
message = 'You selected:\n'
# Determine which Checkbuttons are selected and
# build the message string accordingly:
if cb_var1.get() == 1:
message = message + '1\n'
if cb_var2.get() == 1:
message = message + '2\n'
if cb_var3.get() == 1:
message = message + '3\n'
# Display the message in an info dialog box:
tkinter.messagebox.showinfo('Selection', message)
#EndOfCallback ----------------------------------------------
# Create two frames. One for the checkbuttons
# and another for the regular Button widgets:
top_frame = tkinter.Frame(root)
bottom_frame = tkinter.Frame(root)
# Create three IntVar objects to
# use with the Checkbuttons:
cb_var1 = tkinter.IntVar()
cb_var2 = tkinter.IntVar()
cb_var3 = tkinter.IntVar()
# Set the intVar objects to 0
# (i.e., they are all deselected):
cb_var1.set(0)
cb_var2.set(0)
cb_var3.set(0)
# Create the Checkbutton widgets in the top_frame:
cb1 = tkinter.Checkbutton(top_frame,
text='Option 1',
variable=cb_var1)
cb2 = tkinter.Checkbutton(top_frame,
text='Option 2',
variable=cb_var2)
cb3 = tkinter.Checkbutton(top_frame,
text='Option 3',
variable=cb_var3)
# Pack the Checkbuttons:
cb1.pack()
cb2.pack()
cb3.pack()
# Create an OK button and a Quit button:
ok_button = tkinter.Button(bottom_frame,
text='OK',
command=show_choice)
quit_button = tkinter.Button(bottom_frame,
text='Quit',
command=root.destroy)
# Pack the Buttons:
ok_button.pack(side='left')
quit_button.pack(side='left')
# Pack the frames:
top_frame.pack()
bottom_frame.pack()
# Start the event loop:
root.mainloop()
Provides methods for drawing simple shapes, such as lines, rectangles, ovals, polygons and so on.
The Canvas widget is a blank, rectangular area that allows us to draw simple 2D shapes. Before we can discuss how to draw these shapes, we must understand the screen coordinate system. We must use the Canvas widget's screen coordinate system to specify the location of our graphics.
Everythimg displayed on a computer screen is made up of tiny dots called pixels. The screen coordinate system is used to identify the position of each pixel in an application's window.
Each pixel has an X coordinate and a Y coordinate. The former identifies the pixel's horizontal position, while the latter identifies its vertical position. As usual, the coordinates are written in the form (X, Y).
In the Canvas widget's coordinate system, the coordinates of the pixel in the upper-left corner of the screen are (0, 0) -- that is, the corresponding X and Y coordinates are both 0. The X coordinate increases from left to right, and the Y coordinate increases from top to bottom.
In a window of 640 pixels wide by 480 pixels high, the coordinates of the pixel at the bottom-right corner of the window are (639, 479). In the same window, the coordinates of the pixel in the centre of the window are (319, 239). These are shown in the figure included below.

The Canvas widget has many methods for drawing 2D shapes on the surface of the widget. A sample of such methods is listed below:
create_line
create_rectangle
create_oval
create_arc
create_polygon
create_text
create_line:
¶This draws a line between two or more points on the Canvas. The general syntax for this method:
CanvasName.create_line(x1, y1, x2, y2, options....)
# This program connects multiple points with a line
from tkinter import *
# Create the main window.
root = Tk()
# Create the Canvas widget:
canvas = Canvas(root, width=200, height=200)
# Draw a line connecting multiple points:
# the points are:
# p1 = (10, 10);
# p2 = (189, 10);
# p3 = (100, 189)
canvas.create_line(10, 10, 189, 10, 100, 189, 10, 10)
# can also pass a list as an argument:
# points = [10, 10, 189, 10, 100, 189, 10, 10]
# canvas.draw_line(points)
# Pack the canvas:
canvas.pack()
# Start the mainloop:
root.mainloop()
The output of this code appears below:

create_rectangle:
¶This draws a rectangle on the Canvas. The general syntax for this method:
CanvasName.create_rectangle(x1, y1, x2, y2, options...)
# This program draws a rectangle on a Canvas
from tkinter import *
# Create the main window:
root = Tk()
# Create the Canvas widget:
canvas = Canvas(root, width=200, height=200)
# Draw a rectangle:
points = (20, 20, 180, 180) # coordinates of points
canvas.create_rectangle(points)
# Pack the canvas:
canvas.pack()
# Start the event loop:
root.mainloop()
The output of this code appears below:

create_oval:
¶This draws an oval on the Canvas. The general syntax for this method:
CanvasName.create_oval(x1, y1, x2, y2, options...)

Options indicate several optional keyword arguments that you may pass to the method. A list of such options can be found here The next code demonstrates the use of the create_oval method:
# This program draws two ovals on a Canvas
from tkinter import *
# Create the main window:
root = Tk()
# Create the Canvas widget:
canvas = Canvas(root, width=200, height=200)
# Draw two ovals:
canvas.create_oval(20, 20, 70, 70)
canvas.create_oval(100, 100, 180, 130)
# Pack the canvas.
canvas.pack()
# Start the event loop:
root.mainloop()
The output of this code appears below:

create_arc:
¶This draws an arc on the Canvas. The general syntax for this method:
CanvasName.create_arc(x1, y1, x2, y2, start=angle, extent=width, options...)

Options indicate several optional keyword arguments that you may pass to the method.
A list of such options can be found here.
There are 3 types of arc that we can draw with the style=arcstyle argument, as explained in the above link (to the options of the crate_arc method). The default type
is 'tkinter.PIESLICE'.
The next code demonstrates the basic use of the create_oval method:
# This program draws an arc on a Canvas
from tkinter import *
# Create the main window:
root = Tk()
# Create the Canvas widget:
canvas = Canvas(root, width=200, height=200)
# Draw an arc:
canvas.create_arc(10, 10, 190, 190, start=45, extent=30)
# Pack the canvas:
canvas.pack()
# Start the event loop:
root.mainloop()
The output of this code appears below:

There is a longer example posted on Brightspace (that draws a piechart); the output of that example is included below:

create_polygon:
¶This draws a closed polygon on the Canvas. The general syntax for this method:
CanvasName.create_polygon(x1, y1, x2, y2,... , options...)
# This program draws a polygon on a Canvas
from tkinter import *
# Create the main window:
root = Tk()
# Create the Canvas widget:
canvas = Canvas(root, width=160, height=160)
# Draw a polygon:
points = (60, 20, 100, 20, 140, 60, 140, 100,
100, 140, 60, 140, 20, 100, 20, 60)
canvas.create_polygon(points, fill='blue')
# Pack the canvas:
canvas.pack()
# Start the event loop:
root.mainloop()

create_text:
¶You can use this method to display text on the Canvas. The general syntax for this method:
CanvasName.create_text(x, y, text=YourText, options,...)
# This program draws text on a Canvas
from tkinter import *
# Create the main window:
root = Tk()
# Create the Canvas widget:
canvas = Canvas(root, width=200, height=200)
# Display text in the center of the window:
canvas.create_text(100, 100, text='Hello World')
# Pack the canvas:
canvas.pack()
# Start the mainloop:
root.mainloop()
You can change the font and the alignment of the text. You can find some useful information here
# these lines of code will tell you the font
# families installed on your system:
#
#import tkinter
#import tkinter.font
#tkinter.Tk()
#tkinter.font.families()
In the example below we change the default font to a 20-point boldface Helvetica type:
# This program draws text on a Canvas
from tkinter import *
import tkinter.font # this contains the class 'Font'
# Create the main window:
root = Tk()
# Create the Canvas widget:
canvas = Canvas(root, width=200, height=200)
# Create a font object:
myfont = tkinter.font.Font(family='Helvetica', size=18, weight='bold')
# Display text in the center of the window:
canvas.create_text(100, 100, text='Hello World', font=myfont)
# Pack the canvas:
canvas.pack()
# Start the mainloop:
root.mainloop()

HOMEWORK:
Use the Canvas widget and what has been covered for the past two sessions to write a program that rolls a pair of standard dice. Your program should display the dice graphically and provide two buttons: one for rolling the dice and the other for quitting the program (as seen below).

References:
T. Gaddis: Starting out with Python (4th Edition), Pearson Education Ltd., 2019